#include "Common.h"
#include "PhysicsCommon.h"
#include "CollisionSkin.h"
#include "PhysicsPrimitive.h"
#include "CollisionSystem.h"

using namespace Physics;

CollisionSkin::CollisionSkin(Body* owner)
	: mOwner(owner)
	, mCollisionSystem(NULL)
{
}

CollisionSkin::~CollisionSkin()
{
	RemoveAllPrimitives();
}

int CollisionSkin::AddPrimitive(const Primitive &prim)
{
	mPrimitives.push_back(prim.Clone());

	UpdateWorldBoundingBox();

	return mPrimitives.size() - 1;
}

void CollisionSkin::RemoveAllPrimitives()
{
	for (size_t iPrim = mPrimitives.size() ; iPrim-- != 0 ; )
		delete mPrimitives[iPrim];
	mPrimitives.clear();
}

void CollisionSkin::UpdateWorldBoundingBox()
{
	mWorldBoundingBox.Init();

	for (PrimitiveVector::iterator it(mPrimitives.begin()), end(mPrimitives.end()); it != end; it++)
		(*it)->MergeTo(mWorldBoundingBox);
}

void CollisionSkin::ApplyTransform(const Transform3& transform)
{
	for (PrimitiveVector::iterator it(mPrimitives.begin()), end(mPrimitives.end()); it != end; it++)
		(*it)->SetTransform(transform);
}

bool CollisionSkin::SegmentIntersect(
	float& frac, 
	Vector3 & pos, 
	Vector3 & normal, 
	const Segment & seg) const
{
	Vector3 segEnd = seg.GetEnd();
	frac = SCALAR_HUGE;
	float thisSegLenRelToOrig = 1.0f;
	Segment segCopy(seg);

	for (PrimitiveVector::const_iterator it(mPrimitives.begin()), end(mPrimitives.end()); it != end; it++)
	{
		float thisFrac;
		if ((*it)->SegmentIntersect(thisFrac, pos, normal, segCopy))
		{
			frac = thisFrac * thisSegLenRelToOrig;
			segCopy.Delta *= thisFrac;
			thisSegLenRelToOrig *= frac;
		}
	}

	return (frac <= 1.0f);
}

bool CollisionSkin::SphereIntersect(
	float & frac, 
	Vector3 & pos, 
	Vector3 & normal, 
	const struct Segment & seg,
	float radius) const
{
	Vector3 segEnd = seg.GetEnd();
	frac = SCALAR_HUGE;
	float thisSegLenRelToOrig = 1.0f;
	Segment segCopy(seg);

	for (PrimitiveVector::const_iterator it(mPrimitives.begin()), end(mPrimitives.end()); it != end; it++)
	{
		float thisFrac;
		if ((*it)->SphereIntersect(thisFrac, pos, normal, segCopy, radius))
		{
			frac = thisFrac * thisSegLenRelToOrig;
			segCopy.Delta *= thisFrac;
			thisSegLenRelToOrig *= frac;
		}
	}

	return (frac <= 1.0f);
}